<template>
  <div class="chat-detail-container">
    <!-- 聊天室标题 -->
    <div v-if="currentRoom" class="chat-header">
      <div class="back-button" @click="goBack">
        <span>&lt;</span>
      </div>
      <span>{{ currentRoom.name }}</span>
      <span v-if="currentRoom.type === 'private'" class="chat-status">({{ connectionStatus }})</span>
    </div>
    <div v-else class="chat-header">
      <span>请选择一个聊天室</span>
    </div>

    <!-- 消息列表 -->
    <div class="message-list" ref="messageList">
      <div v-for="(item, index) in processedMessages" :key="index">
        <!-- 时间分割线 -->
        <div v-if="item.type === 'timestamp'" class="timestamp-divider">
          <span>{{ formatTimestamp(item.time) }}</span>
        </div>
        
        <!-- 消息 -->
        <div v-else class="message-item" :class="{ 'self-message': item.username === username }">
          <div class="message-avatar" :class="{ 'group-avatar': currentRoom.type === 'group', 'user-avatar': currentRoom.type === 'private' }">
            <span>{{ item.username.substring(0, 1) }}</span>
          </div>
          <div class="message-content">
            <!-- 只有非自己的消息才显示用户名，且仅在群聊中显示 -->
            <div v-if="item.username !== username && currentRoom.type === 'group'" class="message-username">{{ item.username }}</div>
            <div class="message-bubble" :class="{ 'voice-message': item.messageType === 'voice', 'image-message': item.messageType === 'image', 'video-message': item.messageType === 'video' }" @click="item.messageType === 'voice' && playVoiceMessage(item)">
              <div v-if="item.messageType === 'voice'" class="voice-message-content">
                <div class="voice-icon" :class="{ 'playing': isPlaying(item) }"></div>
                <span class="voice-duration">{{ formatDuration(item.duration) }}"</span>
              </div>
              <div v-else-if="item.messageType === 'image'" class="image-message-content">
                <img :src="item.content" @click="previewImage(item)" :style="getImageStyle(item.imageInfo)" />
              </div>
              <div v-else-if="item.messageType === 'file'" class="file-message-content" @click="downloadFile(item)">
                <div class="file-icon-container">
                  <div class="file-type-icon"></div>
                </div>
                <div class="file-info">
                  <div class="file-name">{{ item.fileInfo.name }}</div>
                  <div class="file-size">{{ formatFileSize(item.fileInfo.size) }}</div>
                </div>
              </div>
              <div v-else-if="item.messageType === 'video'" class="video-message-content" @click="playVideo(item)">
                <div v-if="!isVideoPlaying(item)" class="video-thumbnail">
                  <div class="play-icon"></div>
                  <div class="video-duration">{{ formatDuration(item.videoInfo.duration) }}"</div>
                </div>
                <video v-else :src="item.content" controls autoplay class="video-player"></video>
              </div>
              <div v-else class="message-text">{{ item.content }}</div>
            </div>
          </div>
        </div>
      </div>
      
      <!-- 无消息时显示提示 -->
      <div v-if="processedMessages.length === 0" class="empty-messages">
        <div v-if="currentRoom.type === 'group'">
          群聊已创建，开始聊天吧
        </div>
        <div v-else>
          与 {{ currentRoom.name }} 的私聊已创建，开始聊天吧
        </div>
      </div>
    </div>

    <!-- 输入框区域 -->
    <div v-if="currentRoom" class="message-input-container">
      <div class="message-toolbar">
        <div class="voice-button" @click="toggleInputMode">
          <i :class="isVoiceMode ? 'icon-keyboard' : 'icon-voice'"></i>
        </div>
        
        <div v-if="isVoiceMode" class="voice-input" @touchstart="startVoiceRecord" @touchend="endVoiceRecord">
          <span>{{ isRecording ? '松开 结束' : '按住 说话' }}</span>
        </div>
        
        <div v-else class="text-input-area">
          <input 
            type="text" 
            v-model="inputValue" 
            :placeholder="currentRoom.type === 'private' ? `发送给 ${currentRoom.name}...` : '输入消息...'" 
            @keyup.enter="sendMessage"
            @focus="showEmoji = false"
            ref="textInput"
          >
        </div>
        
        <div class="emoji-button" @click="toggleEmoji">
          <i class="icon-emoji"></i>
        </div>
        
        <div class="send-button" v-if="inputValue.trim()" @click="sendMessage">
          <span>发送</span>
        </div>
        <div class="more-button" v-else @click="toggleMore">
          <i class="icon-more"></i>
        </div>
      </div>
      
      <!-- 表情面板 -->
      <div v-if="showEmoji" class="emoji-panel">
        <div class="emoji-tabs">
          <div class="emoji-tab active">表情</div>
          <div class="emoji-tab">贴图</div>
        </div>
        <div class="emoji-list">
          <div v-for="emoji in emojiList" :key="emoji" class="emoji-item" @click="insertEmoji(emoji)">
            {{ emoji }}
          </div>
        </div>
      </div>
      
      <!-- 更多功能面板 -->
      <div v-if="showMore" class="more-panel">
        <div class="more-item" @click="triggerImageUpload">
          <div class="more-icon photo-icon"></div>
          <span>照片</span>
          <input 
            type="file" 
            ref="imageInput"
            accept="image/*"
            style="display: none"
            @change="handleImageUpload"
          >
        </div>
        <div class="more-item" @click="startVideoRecord">
          <div class="more-icon camera-icon"></div>
          <span>拍摄</span>
        </div>
        <div class="more-item" @click="triggerFileUpload">
          <div class="more-icon file-icon"></div>
          <span>文件</span>
          <input 
            type="file" 
            ref="fileInput"
            style="display: none"
            @change="handleFileUpload"
          >
        </div>
      </div>
    </div>
    
    <!-- 图片预览 -->
    <div v-if="previewImageUrl" class="image-preview" @click="closePreview">
      <img :src="previewImageUrl" />
    </div>
    
    <!-- 录音中提示 -->
    <div v-if="isRecording" class="recording-indicator" :class="{ 'cancel-recording': isCancelRecording }">
      <div class="recording-icon"></div>
      <span>{{ isCancelRecording ? '松开手指，取消发送' : '手指上滑，取消发送' }}</span>
    </div>
    
    <!-- 视频录制界面 -->
    <div 
      v-if="isVideoRecording" 
      class="video-recording-container" 
      @mouseup="stopVideoRecord" 
      @touchend="stopVideoRecord" 
      @touchmove="handleVideoTouchMove"
      @touchstart="recordTouchStart"
    >
      <div class="video-preview-fullscreen">
        <video ref="videoPreview" autoplay muted></video>
        <div class="recording-timer" v-if="isActiveRecording">{{ formatVideoTime(videoRecordTime) }}</div>
        <div class="swipe-hint" :class="{ 'cancel': isCancelVideoRecording }" v-if="isActiveRecording">
          <div class="swipe-icon"></div>
          <span>{{ isCancelVideoRecording ? '松开取消录制' : '向上滑动取消录制' }}</span>
        </div>
      </div>
      
      <!-- 录制按钮和进度环 -->
      <div class="video-record-button-container">
        <div 
          class="video-record-button" 
          @mousedown="resumeVideoRecord" 
          @touchstart.stop="resumeVideoRecord"
        >
          <svg v-if="isActiveRecording" class="record-progress-ring" width="80" height="80" viewBox="0 0 80 80">
            <circle class="record-progress-background" cx="40" cy="40" r="35" />
            <circle 
              class="record-progress-circle" 
              cx="40" 
              cy="40" 
              r="35"
              :style="{ 'stroke-dashoffset': getVideoProgressOffset() }"
            />
          </svg>
          <div class="record-button-inner" :class="{ 'recording': isActiveRecording }"></div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, defineProps, defineEmits, watch, nextTick, computed, onMounted, onBeforeUnmount } from 'vue'
import { useRoute, useRouter } from 'vue-router'

const router = useRouter()
const route = useRoute()

const props = defineProps({
  username: {
    type: String,
    required: true
  },
  currentRoom: {
    type: Object,
    default: null
  },
  messages: {
    type: Array,
    default: () => []
  },
  websocket: {
    type: Object,
    required: true
  },
  roomId: {
    type: String,
    default: ''
  }
})

const emit = defineEmits(['go-back', 'websocket-reconnected'])

const inputValue = ref('')
const messageList = ref(null)
const textInput = ref(null)
const isVoiceMode = ref(false)
const isRecording = ref(false)
const isCancelRecording = ref(false)
const showEmoji = ref(false)
const showMore = ref(false)

// 心跳检测和断线重连相关变量
const heartbeatInterval = ref(null) // 心跳定时器
const reconnectTimeout = ref(null) // 重连定时器
const reconnectAttempts = ref(0) // 重连尝试次数
const maxReconnectAttempts = 10 // 最大重连次数
const reconnectDelay = 3000 // 重连延迟(ms)
const heartbeatDelay = 30000 // 心跳间隔(ms)
const connectionStatus = ref('在线') // 连接状态

// 录音相关变量
const mediaRecorder = ref(null)
const audioChunks = ref([])
const recordStartTime = ref(0)
const currentPlayingMessage = ref(null)
const audioContext = ref(null)
const audioPlayer = ref(null)

// 视频录制相关变量
const isVideoRecording = ref(false)
const videoPreview = ref(null)
const videoRecorder = ref(null)
const videoChunks = ref([])
const videoStream = ref(null)
const videoRecordTime = ref(0)
const videoRecordTimer = ref(null)
const videoBlob = ref(null)
const isActiveRecording = ref(false)
const isCancelVideoRecording = ref(false)
const touchStartY = ref(0) // 触摸开始时的Y坐标

// 视频播放相关变量
const currentPlayingVideo = ref(null)

// 表情列表
const emojiList = [
  '😀', '😃', '😄', '😁', '😆', '😅', '😂', '🤣', '😊', '😇',
  '🙂', '🙃', '😉', '😌', '😍', '🥰', '😘', '😗', '😙', '😚',
  '😋', '😛', '😝', '😜', '🤪', '🤨', '🧐', '🤓', '😎', '🤩',
  '🥳', '😏', '😒', '😞', '😔', '😟', '😕', '🙁', '☹️', '😣',
  '😖', '😫', '😩', '🥺', '😢', '😭', '😤', '😠', '😡', '🤬',
  '🤯', '😳', '🥵', '🥶', '😱', '😨', '😰', '😥', '😓', '🤗',
  '🤔', '🤭', '🤫', '🤥', '😶', '😐', '😑', '😬', '🙄', '😯',
  '😦', '😧', '😮', '😲', '🥱', '😴', '🤤', '😪', '😵', '🤐',
  '🥴', '🤢', '🤮', '🤧', '😷', '🤒', '🤕', '🤑', '🤠', '😈',
  '👿', '👹', '👺', '🤡', '💩', '👻', '💀', '☠️', '👽', '👾'
]

// 图片上传相关变量
const imageInput = ref(null)
const previewImageUrl = ref(null)

// 文件上传相关变量
const fileInput = ref(null)

// 生命周期钩子
onMounted(() => {
  // 初始化WebSocket事件监听
  setupWebSocketListeners()
  // 启动心跳检测
  startHeartbeat()
})

onBeforeUnmount(() => {
  // 清除心跳和重连定时器
  stopHeartbeat()
  stopReconnect()
})

// 设置WebSocket事件监听
function setupWebSocketListeners() {
  // 添加WebSocket连接打开事件监听
  props.websocket.addEventListener('open', handleWebSocketOpen)
  
  // 添加WebSocket连接关闭事件监听
  props.websocket.addEventListener('close', handleWebSocketClose)
  
  // 添加WebSocket错误事件监听
  props.websocket.addEventListener('error', handleWebSocketError)
}

// 处理WebSocket连接打开
function handleWebSocketOpen() {
  console.log('WebSocket连接已打开')
  connectionStatus.value = '在线'
  reconnectAttempts.value = 0 // 重置重连尝试次数
  startHeartbeat() // 启动心跳检测
}

// 处理WebSocket连接关闭
function handleWebSocketClose() {
  console.log('WebSocket连接已关闭')
  connectionStatus.value = '离线'
  stopHeartbeat() // 停止心跳检测
  attemptReconnect() // 尝试重连
}

// 处理WebSocket错误
function handleWebSocketError(error) {
  console.error('WebSocket错误:', error)
  connectionStatus.value = '连接错误'
}

// 启动心跳检测
function startHeartbeat() {
  // 先清除可能存在的心跳定时器
  stopHeartbeat()
  
  // 创建新的心跳定时器
  heartbeatInterval.value = setInterval(() => {
    if (props.websocket.readyState === WebSocket.OPEN) {
      // 发送心跳包
      props.websocket.send(JSON.stringify({
        type: 'heartbeat',
        timestamp: Date.now()
      }))
    } else {
      // 如果连接已关闭，尝试重连
      attemptReconnect()
    }
  }, heartbeatDelay)
}

// 停止心跳检测
function stopHeartbeat() {
  if (heartbeatInterval.value) {
    clearInterval(heartbeatInterval.value)
    heartbeatInterval.value = null
  }
}

// 尝试重新连接
function attemptReconnect() {
  // 如果已经在尝试重连，不重复操作
  if (reconnectTimeout.value) return
  
  // 如果超过最大重连次数，停止尝试
  if (reconnectAttempts.value >= maxReconnectAttempts) {
    console.log('超过最大重连次数，不再尝试重连')
    connectionStatus.value = '重连失败'
    return
  }
  
  // 更新连接状态
  connectionStatus.value = '正在重连...'
  
  // 设置重连定时器
  reconnectTimeout.value = setTimeout(() => {
    reconnectAttempts.value++
    console.log(`尝试重连 (${reconnectAttempts.value}/${maxReconnectAttempts})`)
    
    // 创建新的WebSocket连接
    const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
    const wsUrl = `${wsProtocol}//${window.location.hostname}:3000`
    
    const newWebSocket = new WebSocket(wsUrl)
    
    // 当新连接成功打开时
    newWebSocket.onopen = () => {
      console.log('WebSocket重连成功')
      
      // 更新WebSocket引用
      // 注意：这里我们不能直接修改props，而是需要通知父组件更新
      emit('websocket-reconnected', newWebSocket)
      
      // 重新加入房间
      if (props.currentRoom) {
        newWebSocket.send(JSON.stringify({
          type: 'join',
          username: props.username,
          roomId: props.currentRoom.id,
          roomType: props.currentRoom.type
        }))
      }
      
      // 清除重连状态
      reconnectTimeout.value = null
      reconnectAttempts.value = 0
      connectionStatus.value = '在线'
      
      // 重新设置事件监听
      setupWebSocketListeners()
      
      // 启动心跳
      startHeartbeat()
    }
    
    // 当新连接失败时
    newWebSocket.onerror = () => {
      // 继续尝试重连
      reconnectTimeout.value = null
      attemptReconnect()
    }
  }, reconnectDelay)
}

// 停止重连
function stopReconnect() {
  if (reconnectTimeout.value) {
    clearTimeout(reconnectTimeout.value)
    reconnectTimeout.value = null
  }
}

// 初始化音频上下文
function initAudioContext() {
  if (!audioContext.value) {
    audioContext.value = new (window.AudioContext || window.webkitAudioContext)()
  }
}

// 切换输入模式（语音/文字）
async function toggleInputMode() {
  isVoiceMode.value = !isVoiceMode.value
  showEmoji.value = false
  showMore.value = false
  
  if (!isVoiceMode.value) {
    // 切换到文字输入模式时，聚焦输入框
    nextTick(() => {
      if (textInput.value) {
        textInput.value.focus()
      }
    })
  } else {
    // 请求麦克风权限
    try {
      const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
      initAudioContext()
    } catch (err) {
      console.error('无法访问麦克风：', err)
      isVoiceMode.value = false
      alert('无法访问麦克风，请检查权限设置')
    }
  }
}

// 开始录音
async function startVoiceRecord(event) {
  event.preventDefault()
  if (!isVoiceMode.value) return

  try {
    const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
    mediaRecorder.value = new MediaRecorder(stream)
    audioChunks.value = []
    
    // 设置音频记录器
    setupAudioRecorder(stream)
    
    mediaRecorder.value.start()
    recordStartTime.value = Date.now()
    isRecording.value = true
    isCancelRecording.value = false
    
    // 监听手指移动
    document.addEventListener('touchmove', handleTouchMove)
  } catch (err) {
    console.error('录音失败：', err)
    alert('录音失败，请检查麦克风权限')
  }
}

// 结束录音
function endVoiceRecord(event) {
  event.preventDefault()
  if (!isRecording.value) return
  
  document.removeEventListener('touchmove', handleTouchMove)
  isRecording.value = false
  
  if (mediaRecorder.value && mediaRecorder.value.state === 'recording') {
    mediaRecorder.value.stop()
    // 语音消息保存到本地存储的逻辑在mediaRecorder.onstop回调中处理
  }
}

// 处理手指移动
function handleTouchMove(event) {
  if (!isRecording.value) return
  
  const touch = event.touches[0]
  const startY = event.target.getBoundingClientRect().top
  isCancelRecording.value = touch.clientY < startY - 50
}

// 播放语音消息
async function playVoiceMessage(message) {
  if (!message.messageType === 'voice' || !message.content) return
  
  // 如果正在播放同一条消息，则停止播放
  if (isPlaying(message)) {
    stopPlayingVoice()
    return
  }
  
  // 如果正在播放其他消息，先停止
  if (currentPlayingMessage.value) {
    stopPlayingVoice()
  }
  
  try {
    initAudioContext()
    
    // 创建新的音频元素
    const audio = new Audio(message.content)
    audioPlayer.value = audio
    currentPlayingMessage.value = message
    
    audio.onended = () => {
      currentPlayingMessage.value = null
      audioPlayer.value = null
    }
    
    await audio.play()
  } catch (err) {
    console.error('播放语音失败：', err)
    currentPlayingMessage.value = null
    audioPlayer.value = null
  }
}

// 停止播放语音
function stopPlayingVoice() {
  if (audioPlayer.value) {
    audioPlayer.value.pause()
    audioPlayer.value.currentTime = 0
  }
  currentPlayingMessage.value = null
  audioPlayer.value = null
}

// 检查消息是否正在播放
function isPlaying(message) {
  return currentPlayingMessage.value === message
}

// 格式化语音时长
function formatDuration(seconds) {
  return Math.round(seconds || 0)
}

// 处理消息，添加时间分割线
const processedMessages = computed(() => {
  if (!props.messages || props.messages.length === 0) return []
  
  const result = []
  let lastMessageTime = null
  
  props.messages.forEach((message, index) => {
    const currentTime = new Date(message.time)
    
    // 如果是第一条消息或者与上一条消息间隔超过5分钟，添加时间分割线
    if (index === 0 || !lastMessageTime || (currentTime - lastMessageTime) > 5000) {
      result.push({
        type: 'timestamp',
        time: currentTime
      })
    }
    
    // 添加消息
    result.push(message)
    
    // 更新上一条消息时间
    lastMessageTime = currentTime
  })
  
  return result
})

// 格式化时间戳
function formatTimestamp(timestamp) {
  const date = new Date(timestamp)
  const now = new Date()
  const isToday = date.toDateString() === now.toDateString()
  
  if (isToday) {
    // 今天的消息只显示时间
    return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })
  } else {
    // 非今天的消息显示日期和时间
    return date.toLocaleDateString() + ' ' + date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })
  }
}

// 发送消息
function sendMessage() {
  if (!inputValue.value.trim() || !props.websocket || !props.currentRoom) return;
  
  if (props.websocket.readyState !== WebSocket.OPEN) {
    alert('连接已断开，请刷新页面重试');
    return;
  }
  
  // 发送文本消息
  props.websocket.send(JSON.stringify({
    type: 'message',
    content: inputValue.value.trim()
  }));
  
  // 保存消息到本地存储
  saveMessageToLocalStorage({
    username: props.username,
    content: inputValue.value.trim(),
    time: new Date().toISOString(),
    roomId: props.currentRoom.id,
    roomType: props.currentRoom.type,
    messageType: 'text'
  });
  
  // 清空输入框
  inputValue.value = '';
  
  // 关闭表情面板和更多面板
  showEmoji.value = false;
  showMore.value = false;
}

// 保存消息到本地存储
function saveMessageToLocalStorage(message) {
  try {
    // 获取当前房间ID
    let roomId = props.currentRoom.id;
    
    // 如果是私聊，使用特殊的ID格式
    if (props.currentRoom.type === 'private') {
      roomId = getPrivateRoomId(props.username, props.currentRoom.id);
    }
    
    // 尝试从localStorage加载现有消息
    let chatHistory = localStorage.getItem('chat_history');
    let parsedHistory = chatHistory ? JSON.parse(chatHistory) : {};
    
    // 确保该房间的消息数组已初始化
    if (!parsedHistory[roomId]) {
      parsedHistory[roomId] = [];
    }
    
    // 添加新消息
    parsedHistory[roomId].push(message);
    
    // 保存回localStorage
    localStorage.setItem('chat_history', JSON.stringify(parsedHistory));
  } catch (error) {
    console.error('保存消息到本地存储失败:', error);
  }
}

// 生成私聊房间ID (确保两人之间的ID一致，无论谁发起私聊)
function getPrivateRoomId(user1, user2) {
  return [user1, user2].sort().join('_');
}

function goBack() {
  // 使用路由导航返回聊天列表
  router.push('/chat')
  
  // 同时触发emit事件通知父组件
  emit('go-back')
}

// 滚动到底部
function scrollToBottom() {
  nextTick(() => {
    if (messageList.value) {
      messageList.value.scrollTop = messageList.value.scrollHeight
    }
  })
}

// 监听消息变化，自动滚动到底部
watch(() => props.messages, () => {
  scrollToBottom()
}, { deep: true })

// 组件挂载后滚动到底部
scrollToBottom()

// 触发图片上传
function triggerImageUpload() {
  imageInput.value.click()
}

// 处理图片上传
function handleImageUpload(event) {
  const file = event.target.files[0]
  if (!file) return
  
  const reader = new FileReader()
  reader.onload = (e) => {
    const imageData = e.target.result
    
    // 获取图片尺寸
    const img = new Image()
    img.onload = () => {
      // 准备图片信息
      const imageInfo = {
        width: img.width,
        height: img.height,
        size: file.size
      }
      
      // 发送图片消息
      props.websocket.send(JSON.stringify({
        type: 'image',
        imageData: imageData,
        imageInfo: imageInfo
      }))
      
      // 保存图片消息到本地存储
      saveMessageToLocalStorage({
        username: props.username,
        content: imageData,
        time: new Date().toISOString(),
        roomId: props.currentRoom.id,
        roomType: props.currentRoom.type,
        messageType: 'image',
        imageInfo: imageInfo
      })
    }
    img.src = imageData
  }
  reader.readAsDataURL(file)
  
  // 重置文件输入
  event.target.value = null
  showMore.value = false
}

// 预览图片
function previewImage(message) {
  if (message.messageType === 'image') {
    previewImageUrl.value = message.content
  }
}

// 关闭预览
function closePreview() {
  previewImageUrl.value = null
}

// 计算图片样式
function getImageStyle(imageInfo) {
  if (!imageInfo || !imageInfo.width || !imageInfo.height) {
    return {
      maxWidth: '200px',
      maxHeight: '200px'
    }
  }
  
  const maxWidth = 200
  const maxHeight = 200
  let width = imageInfo.width
  let height = imageInfo.height
  
  // 等比例缩放
  if (width > maxWidth) {
    height = (height * maxWidth) / width
    width = maxWidth
  }
  if (height > maxHeight) {
    width = (width * maxHeight) / height
    height = maxHeight
  }
  
  return {
    width: width + 'px',
    height: height + 'px'
  }
}

// 触发文件上传
function triggerFileUpload() {
  fileInput.value.click()
}

// 处理文件上传
function handleFileUpload(event) {
  const file = event.target.files[0]
  if (!file) return
  
  const reader = new FileReader()
  reader.onload = (e) => {
    const fileData = e.target.result
    
    // 准备文件信息
    const fileInfo = {
      name: file.name,
      size: file.size,
      type: file.type
    }
    
    // 发送文件消息
    props.websocket.send(JSON.stringify({
      type: 'file',
      fileData: fileData,
      fileInfo: fileInfo
    }))
    
    // 保存文件消息到本地存储
    saveMessageToLocalStorage({
      username: props.username,
      content: fileData,
      time: new Date().toISOString(),
      roomId: props.currentRoom.id,
      roomType: props.currentRoom.type,
      messageType: 'file',
      fileInfo: fileInfo
    })
  }
  reader.readAsDataURL(file)
  
  // 重置文件输入
  event.target.value = null
  showMore.value = false
}

// 格式化文件大小
function formatFileSize(bytes) {
  if (bytes < 1024) {
    return bytes + ' B'
  } else if (bytes < 1024 * 1024) {
    return (bytes / 1024).toFixed(1) + ' KB'
  } else {
    return (bytes / (1024 * 1024)).toFixed(1) + ' MB'
  }
}

// 下载文件
function downloadFile(message) {
  if (message.messageType !== 'file' || !message.content) return
  
  // 创建下载链接
  const link = document.createElement('a')
  link.href = message.content
  link.download = message.fileInfo.name
  document.body.appendChild(link)
  link.click()
  document.body.removeChild(link)
}

// 切换更多功能面板
function toggleMore() {
  showMore.value = !showMore.value
  if (showMore.value) {
    showEmoji.value = false // 关闭表情面板
  }
}

// 切换表情面板
function toggleEmoji() {
  showEmoji.value = !showEmoji.value
  if (showEmoji.value) {
    showMore.value = false // 关闭更多功能面板
  }
}

// 插入表情到输入框
function insertEmoji(emoji) {
  inputValue.value += emoji
  // 如果输入框为空，则直接发送表情
  if (inputValue.value.trim() === emoji) {
    sendMessage()
  }
}

// 开始视频录制
async function startVideoRecord() {
  try {
    // 请求摄像头权限，使用前置摄像头，并设置高质量视频
    videoStream.value = await navigator.mediaDevices.getUserMedia({
      audio: true,
      video: { 
        facingMode: 'user',
        width: { ideal: window.innerWidth },
        height: { ideal: window.innerHeight }
      }
    })
    
    // 显示预览
    isVideoRecording.value = true
    
    // 在下一个tick后设置视频源
    nextTick(() => {
      if (videoPreview.value) {
        videoPreview.value.srcObject = videoStream.value
        
        // 设置视频样式以占满整个屏幕
        videoPreview.value.style.width = '100%'
        videoPreview.value.style.height = '100%'
        videoPreview.value.style.objectFit = 'cover'
      }
    })
    
    // 设置录制对象
    videoRecorder.value = new MediaRecorder(videoStream.value)
    videoChunks.value = []
    
    // 设置视频记录器
    setupVideoRecorder()
    
    // 关闭更多面板
    showMore.value = false
  } catch (err) {
    console.error('无法访问摄像头:', err)
    alert('无法访问摄像头，请检查权限设置')
  }
}

// 恢复/开始视频录制
function resumeVideoRecord() {
  if (!videoRecorder.value || isActiveRecording.value) return;
  
  isActiveRecording.value = true;
  isCancelVideoRecording.value = false; // 重置取消状态
  
  // 启动录制
  videoRecorder.value.start();
  console.log('视频录制开始');
}

// 停止视频录制
function stopVideoRecord() {
  if (!isVideoRecording.value || !videoRecorder.value) return
  
  // 如果是取消状态，则执行取消操作
  if (isCancelVideoRecording.value) {
    cancelVideoRecording();
    return;
  }
  
  isVideoRecording.value = false
  isActiveRecording.value = false
  
  if (videoRecorder.value.state === 'recording') {
    videoRecorder.value.stop()
    // 视频消息保存到本地存储的逻辑在videoRecorder.onstop回调中处理
  }
  
  // 停止视频预览
  if (videoStream.value) {
    videoStream.value.getTracks().forEach(track => track.stop())
  }
  
  // 停止计时器
  if (videoRecordTimer.value) {
    clearInterval(videoRecordTimer.value)
  }
  
  // 如果录制时间小于1秒，提示录制时间太短
  if (videoRecordTime.value < 1) {
    alert('录制时间太短')
    closeVideoRecording();
    return
  }
}

// 记录触摸开始位置
function recordTouchStart(event) {
  if (event.touches && event.touches[0]) {
    touchStartY.value = event.touches[0].clientY;
    console.log('触摸开始位置:', touchStartY.value);
  }
}

// 处理视频录制时的手指移动
function handleVideoTouchMove(event) {
  if (!isVideoRecording.value) return;
  
  const touch = event.touches[0];
  if (!touch) return;
  
  const currentY = touch.clientY;
  const moveDistance = touchStartY.value - currentY;
  
  console.log('滑动距离:', moveDistance);
  
  // 如果向上滑动超过100像素，则取消录制并返回聊天室
  if (moveDistance > 100) {
    // 标记为取消录制
    isCancelVideoRecording.value = true;
    // 取消录制并返回聊天室
    cancelVideoRecording();
  } else if (moveDistance > 50) {
    // 超过50像素显示取消提示
    isCancelVideoRecording.value = true;
  } else {
    isCancelVideoRecording.value = false;
  }
}

// 取消视频录制并返回聊天室（向上滑动时调用）
function cancelVideoRecording() {
  console.log('取消视频录制并返回聊天室');
  
  // 停止录制
  if (videoRecorder.value && videoRecorder.value.state === 'recording') {
    videoRecorder.value.stop();
  }
  
  // 停止计时器
  if (videoRecordTimer.value) {
    clearInterval(videoRecordTimer.value);
  }
  
  // 重置状态
  isActiveRecording.value = false;
  isCancelVideoRecording.value = true; // 确保标记为已取消
  
  // 清空视频数据，确保不会发送
  videoChunks.value = [];
  videoBlob.value = null;
  
  // 关闭录制界面，返回聊天室
  closeVideoRecording();
}

// 发送视频录制
function sendVideoRecord() {
  if (!videoBlob.value) return
  
  // 读取视频数据
  const reader = new FileReader()
  reader.onload = (e) => {
    const videoData = e.target.result
    
    // 发送视频消息
    props.websocket.send(JSON.stringify({
      type: 'video',
      videoData: videoData,
      videoInfo: {
        duration: videoRecordTime.value,
        size: videoBlob.value.size,
        type: videoBlob.value.type
      }
    }))
    
    // 关闭视频录制界面
    closeVideoRecording()
  }
  reader.readAsDataURL(videoBlob.value)
}

// 关闭视频录制界面
function closeVideoRecording() {
  isVideoRecording.value = false;
  
  // 停止所有轨道
  if (videoStream.value) {
    videoStream.value.getTracks().forEach(track => track.stop());
  }
  
  videoStream.value = null;
  videoRecorder.value = null;
  videoChunks.value = [];
  videoBlob.value = null;
  
  if (videoRecordTimer.value) {
    clearInterval(videoRecordTimer.value);
    videoRecordTimer.value = null;
  }
}

// 格式化视频时间
function formatVideoTime(seconds) {
  const mins = Math.floor(seconds / 60)
  const secs = seconds % 60
  return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`
}

// 计算倒计时圆环的偏移量
function getCountdownOffset() {
  const totalLength = 283 // 圆的周长
  const remainingTime = 30 - videoRecordTime.value
  const offset = totalLength - (remainingTime / 5) * totalLength
  return offset
}

// 计算录制进度环的偏移量
function getVideoProgressOffset() {
  const circumference = 2 * Math.PI * 35 // 圆周长
  const offset = circumference - (videoRecordTime.value / 30) * circumference
  return offset
}

// 播放视频
function playVideo(message) {
  if (message.messageType !== 'video' || !message.content) return
  
  // 如果点击的是当前正在播放的视频，则停止播放
  if (currentPlayingVideo.value === message) {
    currentPlayingVideo.value = null
    return
  }
  
  // 停止之前播放的视频
  currentPlayingVideo.value = message
}

// 检查视频是否正在播放
function isVideoPlaying(message) {
  return currentPlayingVideo.value === message
}

// 显示增强版权限对话框
function showEnhancedPermissionDialog() {
  // 创建权限提示对话框
  const permissionDialog = document.createElement('div')
  permissionDialog.className = 'permission-dialog'
  
  const content = document.createElement('div')
  content.className = 'permission-content'
  
  const title = document.createElement('h3')
  title.textContent = '需要摄像头权限'
  
  const message = document.createElement('p')
  message.textContent = '请允许访问摄像头以使用拍摄功能。您需要在浏览器弹出的权限请求中点击"允许"。'
  
  // 添加浏览器特定的指导
  const browserInfo = getBrowserInfo()
  const instructions = document.createElement('div')
  instructions.className = 'permission-instructions'
  
  let instructionsHTML = `<p><strong>如何开启摄像头权限：</strong></p>`
  
  if (browserInfo.browser === 'Chrome' || browserInfo.browser === 'Edge') {
    instructionsHTML += `
      <ol>
        <li>点击浏览器地址栏右侧的<strong>锁定/信息图标</strong></li>
        <li>点击<strong>网站设置</strong></li>
        <li>找到<strong>摄像头</strong>权限，选择<strong>允许</strong></li>
        <li>刷新页面并重试</li>
      </ol>
      <div class="browser-image chrome-permission"></div>
    `
  } else if (browserInfo.browser === 'Firefox') {
    instructionsHTML += `
      <ol>
        <li>点击浏览器地址栏左侧的<strong>锁定/信息图标</strong></li>
        <li>点击<strong>连接安全</strong>下的箭头</li>
        <li>点击<strong>更多信息</strong></li>
        <li>在权限部分，找到<strong>使用摄像头</strong>并选择<strong>允许</strong></li>
        <li>刷新页面并重试</li>
      </ol>
    `
  } else if (browserInfo.browser === 'Safari') {
    instructionsHTML += `
      <ol>
        <li>点击浏览器顶部菜单<strong>Safari</strong> > <strong>偏好设置</strong></li>
        <li>选择<strong>网站</strong>标签</li>
        <li>在左侧找到<strong>摄像头</strong></li>
        <li>找到当前网站并设置为<strong>允许</strong></li>
        <li>刷新页面并重试</li>
      </ol>
    `
  } else {
    instructionsHTML += `
      <ol>
        <li>点击浏览器地址栏左侧的锁定/信息图标</li>
        <li>找到摄像头权限设置</li>
        <li>选择"允许"</li>
        <li>刷新页面并重试</li>
      </ol>
    `
  }
  
  // 添加移动设备的说明
  if (isMobileDevice()) {
    instructionsHTML += `
      <p><strong>在移动设备上：</strong></p>
      <ol>
        <li>检查您的系统设置中的应用权限</li>
        <li>确保浏览器应用有摄像头访问权限</li>
        <li>某些移动设备可能需要在设置 > 隐私 > 摄像头中授予权限</li>
      </ol>
    `
  }
  
  instructions.innerHTML = instructionsHTML
  
  const buttons = document.createElement('div')
  buttons.className = 'permission-buttons'
  
  const retryBtn = document.createElement('button')
  retryBtn.className = 'retry-btn'
  retryBtn.textContent = '重新请求权限'
  retryBtn.onclick = () => {
    document.body.removeChild(permissionDialog)
    // 短暂延迟后重新请求
    setTimeout(() => {
      startVideoRecord()
    }, 500)
  }
  
  const closeBtn = document.createElement('button')
  closeBtn.className = 'close-btn'
  closeBtn.textContent = '取消'
  closeBtn.onclick = () => {
    document.body.removeChild(permissionDialog)
  }
  
  buttons.appendChild(retryBtn)
  buttons.appendChild(closeBtn)
  
  content.appendChild(title)
  content.appendChild(message)
  content.appendChild(instructions)
  content.appendChild(buttons)
  permissionDialog.appendChild(content)
  
  document.body.appendChild(permissionDialog)
}

// 获取浏览器信息
function getBrowserInfo() {
  const userAgent = navigator.userAgent
  let browser = 'Unknown'
  
  if (userAgent.indexOf('Chrome') > -1 && userAgent.indexOf('Edg') === -1) {
    browser = 'Chrome'
  } else if (userAgent.indexOf('Firefox') > -1) {
    browser = 'Firefox'
  } else if (userAgent.indexOf('Safari') > -1 && userAgent.indexOf('Chrome') === -1) {
    browser = 'Safari'
  } else if (userAgent.indexOf('Edg') > -1) {
    browser = 'Edge'
  } else if (userAgent.indexOf('MSIE') > -1 || userAgent.indexOf('Trident/') > -1) {
    browser = 'IE'
  }
  
  return { browser }
}

// 检测是否为移动设备
function isMobileDevice() {
  return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
}

// 调整视频尺寸以适应容器
function adjustVideoSize(videoElement) {
  if (!videoElement) return
  
  const videoWidth = videoElement.videoWidth
  const videoHeight = videoElement.videoHeight
  const containerWidth = window.innerWidth
  const containerHeight = window.innerHeight
  
  console.log(`视频原始尺寸: ${videoWidth}x${videoHeight}, 容器尺寸: ${containerWidth}x${containerHeight}`)
  
  // 计算视频的宽高比
  const videoRatio = videoWidth / videoHeight
  const containerRatio = containerWidth / containerHeight
  
  if (videoRatio > containerRatio) {
    // 视频比容器更宽，应该适应高度
    videoElement.style.width = 'auto'
    videoElement.style.height = '100%'
  } else {
    // 视频比容器更高，应该适应宽度
    videoElement.style.width = '100%'
    videoElement.style.height = 'auto'
  }
  
  // 对于横屏视频，如果设备是竖屏，可能需要旋转
  if (videoWidth > videoHeight && window.innerHeight > window.innerWidth) {
    console.log('横屏视频在竖屏设备上，考虑旋转')
  }
}

// 设置视频记录器
function setupVideoRecorder() {
  // 设置数据可用事件
  videoRecorder.value.ondataavailable = (event) => {
    if (event.data.size > 0) {
      videoChunks.value.push(event.data)
    }
  }
  
  // 设置停止事件
  videoRecorder.value.onstop = () => {
    // 如果是取消状态，不处理视频数据
    if (isCancelVideoRecording.value) {
      console.log('视频录制已取消，不发送视频');
      return;
    }
    
    // 确保有视频数据
    if (videoChunks.value.length === 0) {
      console.log('没有视频数据可处理');
      return;
    }
    
    const videoBlob = new Blob(videoChunks.value, { type: 'video/webm' })
    const reader = new FileReader()
    
    reader.onloadend = () => {
      const videoData = reader.result
      
      // 发送视频消息
      props.websocket.send(JSON.stringify({
        type: 'video',
        videoData: videoData,
        videoInfo: {
          duration: videoRecordTime.value
        }
      }))
      
      // 保存视频消息到本地存储
      saveMessageToLocalStorage({
        username: props.username,
        content: videoData,
        time: new Date().toISOString(),
        roomId: props.currentRoom.id,
        roomType: props.currentRoom.type,
        messageType: 'video',
        videoInfo: {
          duration: videoRecordTime.value
        }
      })
    }
    
    reader.readAsDataURL(videoBlob)
  }
  
  // 设置计时器
  videoRecordTime.value = 0
  videoRecordTimer.value = setInterval(() => {
    videoRecordTime.value++
  }, 1000)
}

// 设置音频记录器
function setupAudioRecorder(stream) {
  // 设置数据可用事件
  mediaRecorder.value.ondataavailable = (event) => {
    if (event.data.size > 0) {
      audioChunks.value.push(event.data)
    }
  }
  
  // 设置停止事件
  mediaRecorder.value.onstop = () => {
    if (!isCancelRecording.value) {
      const duration = Math.round((Date.now() - recordStartTime.value) / 1000)
      if (duration < 1) {
        alert('说话时间太短')
        return
      }
      
      const audioBlob = new Blob(audioChunks.value, { type: 'audio/webm' })
      const reader = new FileReader()
      reader.onloadend = () => {
        const audioData = reader.result
        
        // 发送语音消息
        props.websocket.send(JSON.stringify({
          type: 'voice',
          audioData: audioData,
          duration: duration
        }))
        
        // 保存语音消息到本地存储
        saveMessageToLocalStorage({
          username: props.username,
          content: audioData,
          time: new Date().toISOString(),
          roomId: props.currentRoom.id,
          roomType: props.currentRoom.type,
          messageType: 'voice',
          duration: duration
        })
      }
      reader.readAsDataURL(audioBlob)
    }
    
    // 停止所有轨道
    stream.getTracks().forEach(track => track.stop())
  }
}
</script>

<style scoped>
.chat-detail-container {
  height: 100vh; /* 设置为视口高度 */
  width: 100%; /* 确保占满宽度 */
  display: flex;
  flex-direction: column;
  background-color: #f5f5f5;
  position: fixed; /* 保持固定定位 */
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  box-sizing: border-box; /* 确保padding和border不会增加元素总宽度 */
  overflow: hidden; /* 防止整体出现滚动条 */
  padding-bottom: 0; /* 移除底部padding */
  z-index: 100; /* 确保在所有其他元素上方 */
}

.chat-header {
  padding: 15px;
  background-color: #ececec;
  border-bottom: 1px solid #ddd;
  font-weight: bold;
  text-align: center;
  position: relative;
}

.chat-status {
  font-size: 12px;
  color: #07C160;
  margin-left: 5px;
  font-weight: normal;
}

.back-button {
  position: absolute;
  left: 15px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 18px;
  font-weight: bold;
  cursor: pointer;
}

.message-list {
  flex: 1;
  padding: 15px;
  overflow-y: auto; /* 仅消息列表区域可滚动 */
  overflow-x: hidden; /* 禁止水平滚动 */
  background-color: #f5f5f5;
}

/* 时间分割线 */
.timestamp-divider {
  text-align: center;
  margin: 15px 0;
  position: relative;
}

.timestamp-divider span {
  background-color: rgba(0, 0, 0, 0.1);
  border-radius: 10px;
  padding: 2px 10px;
  font-size: 12px;
  color: #666;
  display: inline-block;
}

.message-item {
  display: flex;
  margin-bottom: 15px;
  align-items: flex-start;
}

.self-message {
  flex-direction: row-reverse;
}

.message-avatar {
  width: 40px;
  height: 40px;
  color: white;
  display: flex;
  justify-content: center;
  align-items: center;
  margin: 0 10px;
  flex-shrink: 0;
}

.group-avatar {
  background-color: #07C160;
  border-radius: 4px;
}

.user-avatar {
  background-color: #1989fa;
  border-radius: 50%;
}

.self-message .message-avatar {
  background-color: #1989fa;
}

.message-content {
  display: flex;
  flex-direction: column;
}

.message-username {
  font-size: 12px;
  color: #666;
  margin-bottom: 4px;
}

.message-bubble {
  max-width: 60vw;
  padding: 10px;
  border-radius: 4px;
  background-color: white;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}

.self-message .message-bubble {
  background-color: #95ec69;
}

/* 图片和视频消息不应有背景色 */
.message-bubble.image-message, .message-bubble.video-message {
  background-color: transparent !important;
  padding: 0;
  box-shadow: none;
}

.self-message .message-bubble.image-message, .self-message .message-bubble.video-message {
  background-color: transparent !important;
}

.message-text {
  word-break: break-word;
}

.empty-messages {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;
  color: #999;
  font-size: 14px;
  text-align: center;
  padding: 20px;
}

/* 新的输入区域样式 */
.message-input-container {
  border-top: 1px solid #eaeaea;
  background-color: #f9f9f9;
  position: relative; /* 确保不被tabbar覆盖 */
  z-index: 110; /* 提高层级 */
  bottom: 0;
  padding-bottom: env(safe-area-inset-bottom); /* 适配底部安全区域 */
}

.message-toolbar {
  display: flex;
  align-items: center;
  padding: 8px;
  background-color: #f9f9f9;
}

.voice-button, .emoji-button, .more-button {
  width: 36px;
  height: 36px;
  display: flex;
  justify-content: center;
  align-items: center;
  cursor: pointer;
}

.voice-input {
  flex: 1;
  height: 36px;
  background-color: white;
  border-radius: 4px;
  display: flex;
  justify-content: center;
  align-items: center;
  margin: 0 8px;
  border: 1px solid #ddd;
  color: #666;
  font-size: 14px;
  user-select: none;
  touch-action: none;
}

.text-input-area {
  flex: 1;
  margin: 0 8px;
}

.text-input-area input {
  width: 100%;
  height: 36px;
  padding: 0 10px;
  border: 1px solid #ddd;
  border-radius: 4px;
  outline: none;
  font-size: 14px;
}

.send-button {
  background-color: #07C160;
  color: white;
  border-radius: 4px;
  padding: 0 12px;
  height: 36px;
  display: flex;
  justify-content: center;
  align-items: center;
  cursor: pointer;
  font-size: 14px;
}

/* 图标样式 */
.icon-voice, .icon-keyboard, .icon-emoji, .icon-more {
  width: 24px;
  height: 24px;
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
}

.icon-voice {
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23666"><path d="M12 14c1.66 0 3-1.34 3-3V5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3zm5.91-3c-.49 0-.9.36-.98.85C16.52 14.2 14.47 16 12 16s-4.52-1.8-4.93-4.15c-.08-.49-.49-.85-.98-.85-.61 0-1.09.54-1 1.14.49 3 2.89 5.35 5.91 5.78V20c0 .55.45 1 1 1s1-.45 1-1v-2.08c3.02-.43 5.42-2.78 5.91-5.78.1-.6-.39-1.14-1-1.14z"/></svg>');
}

.icon-keyboard {
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23666"><path d="M20 5H4c-1.1 0-1.99.9-1.99 2L2 17c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm-9 3h2v2h-2V8zm0 3h2v2h-2v-2zM8 8h2v2H8V8zm0 3h2v2H8v-2zm-1 2H5v-2h2v2zm0-3H5V8h2v2zm9 7H8v-2h8v2zm0-4h-2v-2h2v2zm0-3h-2V8h2v2zm3 3h-2v-2h2v2zm0-3h-2V8h2v2z"/></svg>');
}

.icon-emoji {
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23666"><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm3.5-9c.83 0 1.5-.67 1.5-1.5S16.33 8 15.5 8 14 8.67 14 9.5s.67 1.5 1.5 1.5zm-7 0c.83 0 1.5-.67 1.5-1.5S9.33 8 8.5 8 7 8.67 7 9.5 7.67 11 8.5 11zm3.5 6.5c2.33 0 4.31-1.46 5.11-3.5H6.89c.8 2.04 2.78 3.5 5.11 3.5z"/></svg>');
}

.icon-more {
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23666"><path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/></svg>');
}

/* 表情面板 */
.emoji-panel {
  height: 220px;
  background-color: #f0f0f0;
  border-top: 1px solid #ddd;
  overflow: hidden;
}

.emoji-tabs {
  display: flex;
  height: 40px;
  border-bottom: 1px solid #ddd;
}

.emoji-tab {
  flex: 1;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 14px;
  color: #666;
}

.emoji-tab.active {
  color: #07C160;
  border-bottom: 2px solid #07C160;
}

.emoji-list {
  display: flex;
  flex-wrap: wrap;
  padding: 10px;
  height: calc(100% - 40px);
  overflow-y: auto;
}

.emoji-item {
  width: 40px;
  height: 40px;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 24px;
  cursor: pointer;
}

/* 更多功能面板 */
.more-panel {
  display: flex;
  padding: 20px 10px;
  background-color: #f0f0f0;
  border-top: 1px solid #ddd;
}

.more-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin: 0 15px;
  position: relative;
  cursor: pointer;
}

.more-item:active {
  opacity: 0.7;
}

.more-icon {
  width: 50px;
  height: 50px;
  border-radius: 10px;
  margin-bottom: 5px;
  background-color: white;
  display: flex;
  justify-content: center;
  align-items: center;
}

.more-item span {
  font-size: 12px;
  color: #666;
}

.photo-icon, .camera-icon, .file-icon {
  width: 24px;
  height: 24px;
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
}

.photo-icon {
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23666"><path d="M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z"/></svg>');
}

.camera-icon {
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23666"><path d="M12 12c0-1.1.9-2 2-2s2 .9 2 2-.9 2-2 2-2-.9-2-2zm0-9.5C17.52 2.5 22 6.98 22 12.5c0 5.52-4.48 10-10 10S2 18.02 2 12.5C2 6.98 6.48 2.5 12 2.5zm0 18c4.42 0 8-3.58 8-8s-3.58-8-8-8-8 3.58-8 8 3.58 8 8 8z"/></svg>');
}

.file-icon {
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23666"><path d="M6 2c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6H6zm7 7V3.5L18.5 9H13z"/></svg>');
}

/* 语音消息样式 */
.voice-message {
  min-width: 80px;
  cursor: pointer;
}

.voice-message-content {
  display: flex;
  align-items: center;
  gap: 8px;
}

.voice-icon {
  width: 16px;
  height: 16px;
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23666"><path d="M12 14c1.66 0 3-1.34 3-3V5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3z"/><path d="M17 11c0 2.76-2.24 5-5 5s-5-2.24-5-5H5c0 3.53 2.61 6.43 6 6.92V21h2v-3.08c3.39-.49 6-3.39 6-6.92h-2z"/></svg>');
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
}

.voice-icon.playing {
  animation: voicePulse 1s infinite;
}

.voice-duration {
  font-size: 14px;
  color: #666;
}

@keyframes voicePulse {
  0% {
    opacity: 0.5;
  }
  50% {
    opacity: 1;
  }
  100% {
    opacity: 0.5;
  }
}

/* 图片消息样式 */
.image-message-content {
  position: relative;
  max-width: 200px;
  max-height: 200px;
  overflow: hidden;
  border-radius: 4px;
}

.image-message-content img {
  display: block;
  object-fit: cover;
  cursor: pointer;
}

/* 文件消息样式 */
.file-message-content {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  background-color: #e0f2f7;
  border-radius: 8px;
  cursor: pointer;
  transition: background-color 0.2s;
}

.file-message-content:hover {
  background-color: #d0e9f0;
}

.file-icon-container {
  width: 40px;
  height: 40px;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: #b8e994;
  border-radius: 8px;
  flex-shrink: 0;
}

.file-type-icon {
  width: 24px;
  height: 24px;
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
}

.file-type-icon.pdf {
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23666"><path d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm2 12H8V4h6v10zm-2-6H8V8h6v2z"/></svg>');
}

.file-type-icon.doc, .file-type-icon.docx {
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23666"><path d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm2 12H8V4h6v10zm-2-6H8V8h6v2z"/></svg>');
}

.file-type-icon.xls, .file-type-icon.xlsx {
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23666"><path d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm2 12H8V4h6v10zm-2-6H8V8h6v2z"/></svg>');
}

.file-type-icon.zip, .file-type-icon.rar {
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23666"><path d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm2 12H8V4h6v10zm-2-6H8V8h6v2z"/></svg>');
}

.file-type-icon.txt {
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23666"><path d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm2 12H8V4h6v10zm-2-6H8V8h6v2z"/></svg>');
}

.file-info {
  display: flex;
  flex-direction: column;
}

.file-name {
  font-size: 14px;
  font-weight: bold;
  color: #333;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 150px;
}

.file-size {
  font-size: 12px;
  color: #999;
  margin-top: 2px;
}

/* 录音指示器 */
.recording-indicator {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background-color: rgba(0, 0, 0, 0.7);
  color: white;
  padding: 20px;
  border-radius: 10px;
  display: flex;
  flex-direction: column;
  align-items: center;
  transition: background-color 0.3s;
}

.recording-indicator.cancel-recording {
  background-color: rgba(255, 0, 0, 0.7);
}

.recording-icon {
  width: 60px;
  height: 60px;
  margin-bottom: 10px;
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23fff"><path d="M12 14c1.66 0 3-1.34 3-3V5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3z"/><path d="M17 11c0 2.76-2.24 5-5 5s-5-2.24-5-5H5c0 3.53 2.61 6.43 6 6.92V21h2v-3.08c3.39-.49 6-3.39 6-6.92h-2z"/></svg>');
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
  animation: pulse 1.5s infinite;
}

@keyframes pulse {
  0% {
    opacity: 0.5;
  }
  50% {
    opacity: 1;
  }
  100% {
    opacity: 0.5;
  }
}

/* 图片预览 */
.image-preview {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.9);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 1000;
  cursor: pointer;
}

.image-preview img {
  max-width: 90%;
  max-height: 90%;
  object-fit: contain;
}

/* 视频录制界面样式 */
.video-recording-container {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: #000;
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 1000;
  flex-direction: column;
}

.video-preview-fullscreen {
  width: 100%;
  height: 100%;
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: #000;
  overflow: hidden; /* 确保内容不溢出 */
}

.video-preview-fullscreen video {
  width: 100%;
  height: 100%;
  object-fit: cover; /* 使用cover确保填满整个屏幕 */
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
}

/* 竖屏模式下视频占满整个屏幕 */
@media (orientation: portrait) {
  .video-preview-fullscreen video {
    width: 100vw;
    height: 100vh;
  }
}

.recording-timer {
  position: absolute;
  top: 20px;
  right: 20px;
  background-color: rgba(0, 0, 0, 0.5);
  color: white;
  padding: 5px 10px;
  border-radius: 5px;
  font-size: 18px;
  font-weight: bold;
}

/* 滑动提示样式 */
.swipe-hint {
  position: absolute;
  top: 20px;
  left: 50%;
  transform: translateX(-50%);
  background-color: rgba(0, 0, 0, 0.5);
  color: white;
  padding: 8px 15px;
  border-radius: 20px;
  font-size: 14px;
  display: flex;
  align-items: center;
  opacity: 0.8;
  transition: all 0.3s;
}

.swipe-hint.cancel {
  background-color: rgba(255, 59, 48, 0.7);
  transform: translateX(-50%) scale(1.1);
}

.swipe-icon {
  width: 20px;
  height: 20px;
  margin-right: 5px;
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23ffffff"><path d="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z"/></svg>');
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
}

.video-record-button-container {
  position: absolute;
  bottom: 40px; /* 增加底部距离 */
  left: 50%;
  transform: translateX(-50%);
  z-index: 10;
}

/* 录制按钮样式 */
.video-record-button {
  width: 80px;
  height: 80px;
  border-radius: 50%;
  background-color: rgba(0, 0, 0, 0.3);
  display: flex;
  justify-content: center;
  align-items: center;
  position: relative;
  cursor: pointer;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
  transition: background-color 0.2s;
}

.video-record-button:active {
  opacity: 0.8;
}

.record-progress-ring {
  position: absolute;
  width: 100%;
  height: 100%;
}

.record-progress-background {
  fill: none;
  stroke: #fff;
  stroke-width: 5;
  stroke-dasharray: 283; /* 圆的周长 */
  stroke-dashoffset: 0;
}

.record-progress-circle {
  fill: none;
  stroke: #fff;
  stroke-width: 5;
  stroke-dasharray: 283; /* 圆的周长 */
  stroke-dashoffset: 0;
  transition: stroke-dashoffset 0.3s ease-in-out;
}

.record-button-inner {
  width: 60px;
  height: 60px;
  border-radius: 50%;
  background-color: white;
  border: 2px solid #f5f5f5;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
  transition: all 0.3s ease;
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
}

.record-button-inner:before {
  content: '';
  width: 0;
  height: 0;
  border-style: solid;
  border-width: 10px 0 10px 16px;
  border-color: transparent transparent transparent #ff4d4f;
  position: absolute;
  left: 22px;
}

.record-button-inner.recording {
  width: 40px;
  height: 40px;
  background-color: #f5222d; /* 深红色 */
  border: none;
}

.record-button-inner.recording:before {
  display: none;
}

.cancel-icon {
  width: 24px;
  height: 24px;
  position: relative;
}

.cancel-icon:before, .cancel-icon:after {
  content: '';
  position: absolute;
  width: 24px;
  height: 2px;
  background-color: white;
  top: 50%;
  left: 0;
}

.cancel-icon:before {
  transform: rotate(45deg);
}

.cancel-icon:after {
  transform: rotate(-45deg);
}

/* 视频消息样式 */
.video-message-content {
  width: 200px;
  max-width: 100%;
  border-radius: 8px;
  overflow: hidden;
  position: relative;
  cursor: pointer;
}

.video-thumbnail {
  width: 100%;
  height: 120px;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: #333;
}

.video-player {
  width: 100%;
  max-height: 250px;
  display: block;
  background-color: #000;
  border-radius: 8px;
}

.play-icon {
  width: 40px;
  height: 40px;
  background-color: rgba(0, 0, 0, 0.6);
  border-radius: 50%;
  display: flex;
  justify-content: center;
  align-items: center;
  position: relative;
}

.play-icon:before {
  content: '';
  width: 0;
  height: 0;
  border-style: solid;
  border-width: 10px 0 10px 16px;
  border-color: transparent transparent transparent #fff;
  position: absolute;
  left: 14px;
}

.video-duration {
  position: absolute;
  bottom: 5px;
  right: 5px;
  background-color: rgba(0, 0, 0, 0.7);
  color: white;
  padding: 2px 5px;
  border-radius: 4px;
  font-size: 12px;
}

/* 视频播放器覆盖层 */
.video-player-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.9);
  z-index: 1000;
  display: flex;
  justify-content: center;
  align-items: center;
}

.video-player-overlay video {
  max-width: 90%;
  max-height: 80%;
}

.close-video-btn {
  position: absolute;
  top: 20px;
  right: 20px;
  width: 40px;
  height: 40px;
  background-color: rgba(255, 255, 255, 0.3);
  color: white;
  border-radius: 50%;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 24px;
  cursor: pointer;
}

/* 权限对话框样式 */
.permission-dialog {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.7);
  z-index: 1100;
  display: flex;
  justify-content: center;
  align-items: center;
}

.permission-content {
  background-color: white;
  border-radius: 10px;
  padding: 20px;
  width: 90%;
  max-width: 400px;
  max-height: 80%;
  overflow-y: auto;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
}

.permission-content h3 {
  margin-top: 0;
  color: #333;
  font-size: 18px;
  text-align: center;
}

.permission-content p {
  margin: 10px 0;
  color: #666;
  font-size: 14px;
  line-height: 1.5;
}

.permission-instructions {
  background-color: #f5f5f5;
  padding: 15px;
  border-radius: 8px;
  margin: 15px 0;
}

.permission-instructions strong {
  color: #333;
}

.permission-instructions ol {
  margin: 10px 0 10px 20px;
  padding: 0;
}

.permission-instructions li {
  margin-bottom: 10px;
  color: #555;
  font-size: 14px;
  line-height: 1.4;
}

.permission-buttons {
  display: flex;
  gap: 10px;
  margin-top: 20px;
}

.permission-content button {
  flex: 1;
  border: none;
  border-radius: 4px;
  padding: 10px 16px;
  font-size: 14px;
  cursor: pointer;
  transition: background-color 0.2s;
}

.retry-btn {
  background-color: #07C160;
  color: white;
}

.retry-btn:hover {
  background-color: #06a050;
}

.close-btn {
  background-color: #f5f5f5;
  color: #333;
}

.close-btn:hover {
  background-color: #e0e0e0;
}

.browser-image {
  width: 100%;
  height: 100px;
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
  margin: 10px 0;
}

.chrome-permission {
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23666"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm-1-13h2v6h-2zm0 8h2v2h-2z"/></svg>');
}

/* 录制提示样式 */
.recording-hint {
  position: absolute;
  bottom: 120px;
  left: 50%;
  transform: translateX(-50%);
  background-color: rgba(0, 0, 0, 0.5);
  color: white;
  padding: 10px 20px;
  border-radius: 20px;
  font-size: 16px;
  z-index: 10;
}

/* 取消按钮样式 */
.video-cancel-button {
  position: absolute;
  bottom: 30px;
  right: 30px;
  width: 40px;
  height: 40px;
  background-color: rgba(0, 0, 0, 0.5);
  color: white;
  border-radius: 50%;
  display: flex;
  justify-content: center;
  align-items: center;
  cursor: pointer;
}

.video-cancel-button:active {
  background-color: rgba(0, 0, 0, 0.7);
}

/* 连接状态样式 */
.chat-status {
  font-size: 0.8rem;
  margin-left: 0.5rem;
  color: #42b983;
}
.chat-status.offline {
  color: #f56c6c;
}
.chat-status.reconnecting {
  color: #e6a23c;
}
</style> 